#!/bin/bash -n

command -v base64 >/dev/null || {

    { echo -n bash.support.generic.error:' ';
      echo cannot complete source: base64 command not found;
    } >&2;
    
    { base64 2>&1; } >/dev/null; # run the command anyway to get the exit code. 
    
    return
    
} # base64 support is required to encode arrays as values.

hash base64; 

declare -A error=0; error() { 

    # error ID_TAG
    # error reset
    # error identify ID_TAG = INT_VALUE[: message]

    # message may contain shell substitutions to be expanded on presentation.
    
    declare -pA error 2>&1 >/dev/null || declare -gA error=0;
    
    # reset error status
    [[ $1 = reset ]] && {
        error=0;
        unset error[title] error[description] error[source] error[message];
        return 0;    
    }
    
    [[ -n ${error[messages]} ]] || {
        local -A error_message="" error_message[1]="general operation failure";
        error[messages]="$(declare -p error_message | base64 -w 0)";
    }
    
    [[ -n ${error[codes]} ]] || {
        local -A error_code[OK]=0;
        error[codes]="$(declare -p error_code | base64 -w 0)";
    }
    
    source <(base64 -d <<<"${error[messages]}") # declare error_message
    source <(base64 -d <<<"${error[codes]}") # declare error_code
        
    [[ $1 = identify ]] && { # error identify id = value: [message]
        (( $# >= 4 )) || {
            echo $0: error: not enough arguments to: error identify >&2;
            return 1; # screwed up
        } && {
            local id=$2 code=${4}; shift 4;
            error_code[$id]=${code/:/};
            error[codes]="$(declare -p error_code | base64 -w 0)";            
            [[ $code =~ :$ ]] && {
                error_message[$id]="$@";
                error[messages]="$(declare -p error_message | base64 -w 0)";            
            }
        }
        return;
    }
                
    error=${error_code[$1]};
    
    [[ -n ${error[title]} ]] || {
        error[title]="$0";
    }
    
    [[ -n ${error[description]} ]] || {
        error[description]="error ${error:=tag \'$1\'}";
    }
    
    [[ -n ${error[message]} ]] || {
        error[message]="$(eval echo "${error_message[$1]:=unexplained error}")";
    }
    
    error_handler "$@" && {
    
        echo ${error[title]}: ${error[description]}: ${error[message]} >&2;
        
        [[ -n ${error[source]} ]] && {
            echo ""
            echo "Error Source:";
            echo "";
            echo "${error[source]}";
        } >&2;
                        
    }
    
    (( $error > 255 )) && return 255;
    
    return $error;
    
}

function error_handler() {
    : # stub function
}

